#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <pwd.h>
#include <netinet/in.h>
#include <time.h>
#include <dirent.h>
#include <errno.h>
#include <stdbool.h>

#ifndef BSIZE
#define BSIZE 1024
#endif

//Customized FTP Server Root Path
#define SERVERROOTPATH "/home/DaiKunling"

#ifndef DIR_AUTH_MODE
#define DIR_AUTH_MODE (S_IRWXU|S_IRWXG|S_IRWXO)
#endif

#ifndef USERNAME_LENGTH
#define USERNAME_LENGTH 32
#endif

#ifndef USERIP_LENGTH
#define USERIP_LENGTH 30
#endif

typedef struct Port
{
    int p1;
    int p2;
} Port;

typedef struct State
{
    /* Connection mode: NORMAL, SERVER, CLIENT */
    int mode;
    int userLevel;

    /* Is user loggd in? */
    int logged_in;

    /* Is this username allowed? */
    int username_ok;
    char *username;
    char *userIP;

    /* Response message to client e.g. 220 Welcome */
    char *message;

    /* Commander connection */
    int connection;

    /* Socket for passive connection (must be accepted later) */
    int sock_pasv;

    /* Transfer process id */
    int tr_pid;

    //socket for active connection
    int sock_active;

    //port for active connection
    int port_active;


    /* RNFR Old file name*/
    char *oldName;

} State;


/* Command struct */
typedef struct Command
{
    char command[5];
    char arg[BSIZE];
} Command;

/**
* Connection mode
* NORMAL - normal connection mode, nothing to transfer
* SERVER - passive connection (PASV command), server listens
* CLIENT - server connects to client (PORT command)
*/
typedef enum conn_mode{ NORMAL, SERVER, CLIENT }conn_mode;

/* Commands enumeration */
typedef enum cmdlist 
{ 
    ABOR, CWD, DELE, LIST, MDTM, MKD, NLST, PASS, PASV,
    PORT, PWD, QUIT, RETR, RMD, RNFR, RNTO, SITE, SIZE,
    STOR, TYPE, USER, NOOP
} cmdlist;

/* String mappings for cmdlist */
static const char *cmdlist_str[] = 
{
    "ABOR", "CWD", "DELE", "LIST", "MDTM", "MKD", "NLST", "PASS", "PASV",
    "PORT", "PWD", "QUIT", "RETR", "RMD", "RNFR", "RNTO", "SITE", "SIZE",
    "STOR", "TYPE", "USER", "NOOP"
};

/* Valid usernames for anonymous ftp */
static const char *usernames[] = 
{
    "ftp","anonymous","public","anon","test","foo","root"
};

/* Permission strings*/
static const char *perm[]={"---","--x","-w-","-wx","r--","r-x","rw-","rwx"};

/* Server functions */
void gen_port(Port *);
void gen_port2(char *p, Port *port);
void parse_command(char *, Command *);
int create_socket(int port);
void write_state(State *);
int accept_connection(int);

/* Commands handle functions*/
void response(Command *, State *);
void ftp_user(Command *, State *);
void ftp_pass(Command *, State *);
void ftp_pwd(Command *, State *);
void ftp_cwd(Command *, State *);
void ftp_mkd(Command *, State *);
void ftp_rmd(Command *, State *);
void ftp_pasv(Command *, State *);
void ftp_list(Command *, State *);
void ftp_retr(Command *, State *);
void ftp_stor(Command *, State *);
void ftp_dele(Command *, State *);
void ftp_size(Command *, State *);
void ftp_quit(State *);
void ftp_type(Command *, State *);
void ftp_abor(State *);
void ftp_rnfr(Command *, State *);
void ftp_rnto(Command *, State *);
void ftp_port(Command *, State *);
void ftp_noop(Command *, State *);

void list_proc(DIR *dp,int *connection );

int delay_download(int fd, int connection);
int delay_upload(int fd, int connection);

void str_perm(int, char *);
bool auth_check(State *, bool isRootNeed, bool isLoginNeed);
void my_wait(int);
double calc_time_interval_ms(struct timeval *start_time, struct timeval *end_time);
void print_traffic_info(double time_ms , int traffic_byte);
int mk_dir(char *dir);


void getip(int sock, int *ip);
void get_peer_ip(int sock, int *ip);
void getip_ascii(int sock, char* ip_str);
void get_peer_ip_ascii(int sock, char* ip_str);
